package com.bsbc.project.config;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

/**
 * spring aop 切面类
 */
@Aspect
@SpringBootConfiguration
public class AopHandler {

    /**
     *  切点表达式
     */
    @Pointcut("@annotation(com.bsbc.project.config.OperationAuth)")
    public void poinCunt() {

    }

    /**
     * spring aop 环绕通知处理带有 operationAuth 注解的方法返回的数据
     *
     * ProceedingJoinPoint 暴露proceed方法 该方法的作用: 让目标方法执行
     * 能决定是否走代理链还是走自己拦截的其他逻辑
     * @return
     */
    @Around("poinCunt()")
    public Object dataHandler(ProceedingJoinPoint joinPoint)throws Throwable {
        System.out.println("spring aop 环绕通知开始");
        //todo 代理链的执行逻辑
        Object proceed = joinPoint.proceed();
        // instanceof java 关键字: 左边是对象，右边是类；当对象是右边类或子类所创建对象时，返回true；否则，返回false
        if (proceed instanceof List) {
            //方法结果集
            List<?> result = (List<?>)proceed;
            //获取带有自定义注解的方法信息
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            System.out.println("方法名：" + method.getName());
            //获取方法注解
            OperationAuth annotation = method.getAnnotation(OperationAuth.class);
            //利用反射将结果集中的value字段赋值
            this.setValue(result,annotation);
        }
        return proceed;
    }

    public List<?> setValue(List<?> list,OperationAuth operationAuth)throws Throwable {
        for (Object o : list) {
            Class<?> clazz = o.getClass();
            //将结果集中的性别字段进行转换
            //获取sex字段值
            Method sex = clazz.getMethod("getSex");
            Integer sexCode = (Integer) sex.invoke(o);
            //设置sexDesc字段值
            Field sexDesc = clazz.getDeclaredField("sexDesc");
            sexDesc.setAccessible(true);
            sexDesc.set(o,sexCode == 1 ? "男" : "女");
            Field value = clazz.getDeclaredField("value");
            value.setAccessible(true);
            value.set(o,operationAuth.value());
        }
        return list;
    }
}
